﻿using System;
using System.Web.Routing;
using ManagedUIFlow.Application;
using Xunit;

namespace ManagedUIFlow.Specs.Application
{
    public class RouteCollectionExtensionsSpecs
    {
        private static readonly string[] NameSpaces = new[] { "nsA.nsB.nsC", "ns1.ns2.ns3" };

        [Fact]
        public void MapFlow3()
        {
            var routes = new RouteCollection();

            routes.MapFlow("RouteName", "SomeUrl");

            Assert.Equal(1, routes.Count);
            var route = routes[0] as Route;
            Assert.NotNull(route);
            Assert.Null(route.DataTokens);
            Assert.Same(route, routes["RouteName"]);
            Assert.Equal("SomeUrl", route.Url);
            Assert.IsType(typeof(AppRouteHandler), route.RouteHandler);
            Assert.Equal(0, route.Defaults.Count);
            Assert.Equal(0, route.Constraints.Count);
        }

        [Fact]
        public void MapFlow3WithNameSpaces()
        {
            var routes = new RouteCollection();

            routes.MapFlow("RouteName", "SomeUrl", NameSpaces);

            Assert.Equal(1, routes.Count);
            var route = routes[0] as Route;
            Assert.NotNull(route);
            Assert.NotNull(route.DataTokens);
            Assert.NotNull(route.DataTokens["Namespaces"]);
            var routeNameSpaces = route.DataTokens["Namespaces"] as string[];
            Assert.Equal(routeNameSpaces.Length, 2);
            Assert.Same(route, routes["RouteName"]);
            Assert.Same(routeNameSpaces, NameSpaces);
            Assert.Equal("SomeUrl", route.Url);
            Assert.IsType(typeof(AppRouteHandler), route.RouteHandler);
            Assert.Equal(0, route.Defaults.Count);
            Assert.Equal(0, route.Constraints.Count);
        }

        [Fact]
        public void MapFlow3WithEmptyNameSpaces()
        {
            var routes = new RouteCollection();

            routes.MapFlow("RouteName", "SomeUrl", new string[] { });

            Assert.Equal(1, routes.Count);
            var route = routes[0] as Route;
            Assert.NotNull(route);
            Assert.Null(route.DataTokens);
            Assert.Same(route, routes["RouteName"]);
            Assert.Equal("SomeUrl", route.Url);
            Assert.IsType(typeof(AppRouteHandler), route.RouteHandler);            
            Assert.Equal(0, route.Defaults.Count);
            Assert.Equal(0, route.Constraints.Count);
        }

        [Fact]
        public void MapFlow4()
        {
            var routes = new RouteCollection();
            var defaults = new { Foo = "DefaultFoo" };

            routes.MapFlow("RouteName", "SomeUrl", defaults);

            Assert.Equal(1, routes.Count);
            var route = routes[0] as Route;
            Assert.NotNull(route);
            Assert.Null(route.DataTokens);
            Assert.Same(route, routes["RouteName"]);
            Assert.Equal("SomeUrl", route.Url);
            Assert.IsType(typeof(AppRouteHandler), route.RouteHandler);                        
            Assert.Equal("DefaultFoo", route.Defaults["Foo"]);
            Assert.Equal(0, route.Constraints.Count);
        }

        [Fact]
        public void MapFlow4WithNameSpaces()
        {
            var routes = new RouteCollection();
            var defaults = new { Foo = "DefaultFoo" };

            routes.MapFlow("RouteName", "SomeUrl", defaults, NameSpaces);

            Assert.Equal(1, routes.Count);
            var route = routes[0] as Route;
            Assert.NotNull(route);
            Assert.NotNull(route.DataTokens);
            Assert.NotNull(route.DataTokens["Namespaces"]);
            var routeNameSpaces = route.DataTokens["Namespaces"] as string[];
            Assert.Equal(routeNameSpaces.Length, 2);
            Assert.Same(route, routes["RouteName"]);
            Assert.Same(routeNameSpaces, NameSpaces);
            Assert.Equal("SomeUrl", route.Url);
            Assert.IsType(typeof(AppRouteHandler), route.RouteHandler);                                    
            Assert.Equal("DefaultFoo", route.Defaults["Foo"]);
            Assert.Equal(0, route.Constraints.Count);
        }

        [Fact]
        public void MapFlow5()
        {
            var routes = new RouteCollection();
            var defaults = new { Foo = "DefaultFoo" };
            var constraints = new { Foo = "ConstraintFoo" };

            routes.MapFlow("RouteName", "SomeUrl", defaults, constraints);

            Assert.Equal(1, routes.Count);
            var route = routes[0] as Route;
            Assert.NotNull(route);
            Assert.Null(route.DataTokens);
            Assert.Same(route, routes["RouteName"]);
            Assert.Equal("SomeUrl", route.Url);
            Assert.IsType(typeof(AppRouteHandler), route.RouteHandler);            
            Assert.Equal("DefaultFoo", route.Defaults["Foo"]);
            Assert.Equal("ConstraintFoo", route.Constraints["Foo"]);
        }

        [Fact]
        public void MapFlow5WithNullRouteCollectionThrows()
        {
            Assert.Throws<ArgumentNullException>(() => RouteCollectionExtensions.MapFlow(null, null, null, null, null));
        }

        [Fact]
        public void MapRoute5WithNullUrlThrows()
        {
            Assert.Throws<ArgumentNullException>(() => new RouteCollection().MapFlow(null, null /* url */, null, null));
        }
    }
}
